#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>

//用于获取key值的参数
const char* pathname = "/home";
const int proj_id = 1;

#define SHM_SIZE 4096   //共享内存的大小

key_t get_shmkey()
{
    key_t ret = ftok(pathname, proj_id);
    if (ret == -1)
    {
        std::cerr << "get_shmkey failed, errno: " << errno << "errstring: " << strerror(errno) << std::endl;
        exit(1);
    }

    return ret;
}

//将key转换为16进制
std::string to_hexa(key_t key)
{
    char buff[1024] = {0};
    snprintf(buff, 1024, "0x%x", key);

    return buff;
}


int shmid_creatordie(int key, int size, int flag)
{
    int ret = shmget(key, size, flag);
    if (ret == -1)
    {
        std::cerr << "shmid_creatordie failed, errno: " << errno << "errstring: " << strerror(errno) << std::endl;
        exit(1);
    }

    return ret;
}

//创建共享内存——server
int creat_shmid(int key, int size)
{
    //服务端需要创建一个新的共享内存
    return shmid_creatordie(key, size, IPC_CREAT | IPC_EXCL | 0666);
}

//获取共享内存——client
int get_shmid(int key, int size)
{
    //客户端需要拿到已经创建好了的共享内存
    return shmid_creatordie(key, size, IPC_CREAT);
}

//共享内存关联进程
void* shmattch(int shmid)
{
    void* ret = shmat(shmid, nullptr, 0);
    if (ret == (void*)(-1))
    {
        std::cerr << "shmattch failed, errno: " << errno << "errstring: " << strerror(errno) << std::endl;
        exit(1);
    }

    return ret;
}

//取消共享内存和进程的关联
void shm_unattch(const void* address)
{
    int ret = shmdt(address);
    if (ret == -1)
    {
        std::cerr << "shm_unattch failed, errno: " << errno << "errstring: " << strerror(errno) << std::endl;
        exit(-1);
    }
}


//删除共享内存
void shm_delete(int shmid)
{
    int ret = shmctl(shmid, IPC_RMID, nullptr);
    if (ret == -1)
    {
        std::cerr << "shm_delete failed, errno: " << errno << "errstring: " << strerror(errno) << std::endl;
        exit(1);
    }
}

//打印共享内存属性信息
void shm_debug(int shmid)
{
    struct shmid_ds shmds;
    int ret = shmctl(shmid, IPC_STAT, &shmds);
    if (ret == -1)
    {
        std::cerr << "shm_debug failed, errno: " << errno << "errstring: " << strerror(errno) << std::endl;
        exit(1);
    }

    std::cout << "shmds.shm_segsz: " << shmds.shm_segsz << std::endl;
    std::cout << "shmds.shm_nattch:" << shmds.shm_nattch << std::endl;
    std::cout << "shmds.shm_ctime:" << shmds.shm_ctime << std::endl;
    std::cout << "shmds.shm_perm.__key:" << to_hexa(shmds.shm_perm.__key) << std::endl;
}

